package com.yangchuang.openpicture.util;

import jakarta.annotation.Resource;
import org.springframework.data.redis.connection.DataType;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;


/**
 * Redis 工具类 - 优化版
 * 遵循“见名知意”原则，提供更丰富、语义更明确的API。
 */
@Component
public class RedisUtils {

    // Spring 通过 @Resource 注解在构造函数执行后注入 RedisTemplate
    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    // ==================== 操作类懒加载字段 ====================
    private volatile StringOps stringOps;
    private volatile SetOps setOps;
    private volatile HashOps hashOps;
    private volatile ListOps listOps;
    private volatile ZSetOps zSetOps;
    private volatile KeysOps keysOps;

    // ==================== 操作类访问入口 ====================

    /**
     * 获取 String（字符串）类型的操作对象
     */
    public StringOps stringOps() {
        if (stringOps == null) {
            synchronized (this) {
                if (stringOps == null) {
                    stringOps = new StringOps(redisTemplate.opsForValue(), redisTemplate);
                }
            }
        }
        return stringOps;
    }

    /**
     * 获取 Set（集合）类型的操作对象
     */
    public SetOps setOps() {
        if (setOps == null) {
            synchronized (this) {
                if (setOps == null) {
                    setOps = new SetOps(redisTemplate.opsForSet(), redisTemplate);
                }
            }
        }
        return setOps;
    }

    /**
     * 获取 Hash（哈希/散列）类型的操作对象
     */
    public HashOps hashOps() {
        if (hashOps == null) {
            synchronized (this) {
                if (hashOps == null) {
                    hashOps = new HashOps(redisTemplate.opsForHash(), redisTemplate);
                }
            }
        }
        return hashOps;
    }

    /**
     * 获取 List（列表）类型的操作对象
     */
    public ListOps listOps() {
        if (listOps == null) {
            synchronized (this) {
                if (listOps == null) {
                    listOps = new ListOps(redisTemplate.opsForList(), redisTemplate);
                }
            }
        }
        return listOps;
    }

    /**
     * 获取 ZSet（有序集合）类型的操作对象
     */
    public ZSetOps zSetOps() {
        if (zSetOps == null) {
            synchronized (this) {
                if (zSetOps == null) {
                    zSetOps = new ZSetOps(redisTemplate.opsForZSet(), redisTemplate);
                }
            }
        }
        return zSetOps;
    }

    /**
     * 获取针对 Key 的通用操作对象
     */
    public KeysOps keyOps() {
        if (keysOps == null) {
            synchronized (this) {
                if (keysOps == null) {
                    keysOps = new KeysOps(redisTemplate);
                }
            }
        }
        return keysOps;
    }

    // ==================== String (字符串) 操作 ====================

    public static class StringOps {

        private final ValueOperations<String, Object> ops;
        private final RedisTemplate<String, Object> redisTemplate;

        public StringOps(ValueOperations<String, Object> ops, RedisTemplate<String, Object> redisTemplate) {
            this.ops = ops;
            this.redisTemplate = redisTemplate;
        }

        /**
         * 设置一个 String 类型的值 (SET)
         * key不存在就创建
         *
         * @param key   键
         * @param value 值
         */
        public void setValue(String key, Object value) {
            if (key == null || value == null) return;
            ops.set(key, value);
        }

        /**
         * 设置 String 类型的值，并指定过期时间 (SETEX)
         * key不存在就创建
         *
         * @param key     键
         * @param value   值
         * @param timeout 过期时间数值
         * @param unit    时间单位
         */
        public void setValueAndExpire(String key, Object value, long timeout, TimeUnit unit) {
            if (key == null || value == null) return;
            ops.set(key, value, timeout, unit);
        }


        /**
         * 仅当 Key 不存在时，设置 String 类型的值 (SETNX)
         * 我想设置一个值，但前提是这个key必须不存在
         *
         * @param key   键
         * @param value 值
         * @return 如果设置成功返回 true，如果 Key 已存在则返回 false
         */
        public boolean setValueIfAbsent(String key, Object value) {
            if (key == null || value == null) return false;
            return Boolean.TRUE.equals(ops.setIfAbsent(key, value));
        }

        /**
         * 仅当 Key 不存在时设置值，并指定过期时间（原子操作）
         * 我想设置一个值，但前提是这个key必须不存在
         *
         * @param key     键
         * @param value   值
         * @param timeout 过期时间
         * @param unit    时间单位
         * @return 是否设置成功
         */
        public boolean setValueIfAbsentAndExpire(String key, Object value, long timeout, TimeUnit unit) {
            if (key == null || value == null) return false;
            return Boolean.TRUE.equals(ops.setIfAbsent(key, value, timeout, unit));
        }

        /**
         * 获取 String 类型的值 (GET)
         *
         * @param key 键
         * @return 键对应的值，不存在则返回 null
         */
        @SuppressWarnings("unchecked")
        public <T> T getValue(String key) {
            if (key == null) return null;
            return (T) ops.get(key);
        }

        /**
         * 批量设置键值对 (MSET)
         *
         * @param map 包含多个键值对的 Map
         */
        public void setMultipleValues(Map<String, Object> map) {
            if (map == null || map.isEmpty()) return;
            ops.multiSet(map);
        }

        /**
         * 批量获取多个 Key 的值 (MGET)
         *
         * @param keys 键的集合
         * @return 值的列表，顺序与传入的 keys 一致，若某个 key 不存在，对应位置为 null
         */
        public List<Object> getMultipleValues(Collection<String> keys) {
            if (keys == null || keys.isEmpty()) return Collections.emptyList();
            return ops.multiGet(keys);
        }

        /**
         * 对一个整数或浮点数类型的 String 值进行原子增加 (INCRBY)
         *
         * @param key   键
         * @param delta 增加的数值（可以为负数，表示减少）
         * @return 增加后的值
         */
        public Long incrementBy(String key, long delta) {
            if (key == null) return null;
            return ops.increment(key, delta);
        }

        /**
         * 对一个整数或浮点数类型的 String 值进行原子减少 (DECRBY)
         *
         * @param key   键
         * @param delta 减少的数值
         * @return 减少后的值
         */
        public Long decrementBy(String key, long delta) {
            if (key == null) return null;
            return ops.increment(key, -delta);
        }

        /**
         * 获取值的字符串长度 (STRLEN)
         *
         * @param key 键
         * @return 值的长度, key不存在时返回0
         */
        public Long getValueLength(String key) {
            if (key == null) return 0L;
            return ops.size(key);
        }
    }

    // ==================== Set (集合) 操作 ====================

    public static class SetOps {

        private final SetOperations<String, Object> ops;
        private final RedisTemplate<String, Object> redisTemplate;

        public SetOps(SetOperations<String, Object> ops, RedisTemplate<String, Object> redisTemplate) {
            this.ops = ops;
            this.redisTemplate = redisTemplate;
        }

        /**
         * 向 Set 中添加一个或多个成员 (SADD)
         *
         * @param key     键
         * @param members 成员
         * @return 成功添加的成员数量
         */
        public Long addMembers(String key, Object... members) {
            if (key == null || members == null || members.length == 0) return 0L;
            return ops.add(key, members);
        }

        /**
         * 向 Set 添加成员，并为整个 Set 设置过期时间
         * 注意：TTL 是绑定在 Key 上的。每次调用此方法都会重置该 Key 的过期时间。
         *
         * @param key     键
         * @param timeout 过期时间数值
         * @param unit    时间单位
         * @param members 成员
         */
        public void addMembersAndExpire(String key, long timeout, TimeUnit unit, Object... members) {
            if (key == null || members == null || members.length == 0) return;
            ops.add(key, members);
            redisTemplate.expire(key, timeout, unit);
        }

        /**
         * 获取 Set 中的所有成员 (SMEMBERS)
         *
         * @param key 键
         * @return 成员的 Set 集合
         */
        public Set<Object> getAllMembers(String key) {
            if (key == null) return Collections.emptySet();
            return ops.members(key);
        }

        /**
         * 判断一个成员是否存在于 Set 中 (SISMEMBER)
         *
         * @param key    键
         * @param member 成员
         * @return true 表示存在，false 表示不存在
         */
        public boolean isMember(String key, Object member) {
            if (key == null || member == null) return false;
            return Boolean.TRUE.equals(ops.isMember(key, member));
        }

        /**
         * 从 Set 中移除一个或多个成员 (SREM)
         *
         * @param key     键
         * @param members 要移除的成员
         * @return 成功移除的成员数量
         */
        public Long removeMembers(String key, Object... members) {
            if (key == null || members == null || members.length == 0) return 0L;
            return ops.remove(key, members);
        }

        /**
         * 随机弹出一个成员并从 Set 中移除 (SPOP)
         *
         * @param key 键
         * @return 被弹出的成员
         */
        public Object popRandomMember(String key) {
            if (key == null) return null;
            return ops.pop(key);
        }

        /**
         * 随机获取一个成员，但不移除 (SRANDMEMBER)
         *
         * @param key 键
         * @return 随机获取的成员
         */
        public Object getRandomMember(String key) {
            if (key == null) return null;
            return ops.randomMember(key);
        }

        /**
         * 随机获取指定数量的成员，但不移除 (SRANDMEMBER count)
         *
         * @param key   键
         * @param count 获取数量
         * @return 随机成员列表
         */
        public List<Object> getRandomMembers(String key, long count) {
            if (key == null || count <= 0) return Collections.emptyList();
            return ops.randomMembers(key, count);
        }


        /**
         * 获取 Set 的大小（成员数量） (SCARD)
         *
         * @param key 键
         * @return 成员数量
         */
        public Long getMemberCount(String key) {
            if (key == null) return 0L;
            return ops.size(key);
        }

        /**
         * 计算两个 Set 的差集 (SDIFF)
         *
         * @param key      第一个 Set 的键
         * @param otherKey 第二个 Set 的键
         * @return 差集结果
         */
        public Set<Object> getDifference(String key, String otherKey) {
            if (key == null || otherKey == null) return Collections.emptySet();
            return ops.difference(key, otherKey);
        }

        /**
         * 计算两个 Set 的交集 (SINTER)
         *
         * @param key      第一个 Set 的键
         * @param otherKey 第二个 Set 的键
         * @return 交集结果
         */
        public Set<Object> getIntersect(String key, String otherKey) {
            if (key == null || otherKey == null) return Collections.emptySet();
            return ops.intersect(key, otherKey);
        }

        /**
         * 计算两个 Set 的并集 (SUNION)
         *
         * @param key      第一个 Set 的键
         * @param otherKey 第二个 Set 的键
         * @return 并集结果
         */
        public Set<Object> getUnion(String key, String otherKey) {
            if (key == null || otherKey == null) return Collections.emptySet();
            return ops.union(key, otherKey);
        }
    }


    // ==================== Hash (哈希/散列) 操作 ====================

    public static class HashOps {

        private final HashOperations<String, Object, Object> ops;
        private final RedisTemplate<String, Object> redisTemplate;

        public HashOps(HashOperations<String, Object, Object> ops, RedisTemplate<String, Object> redisTemplate) {
            this.ops = ops;
            this.redisTemplate = redisTemplate;
        }

        /**
         * 在 Hash 中设置一个字段的值，如果字段已存在则覆盖 (HSET)
         *
         * @param key   键
         * @param field 字段
         * @param value 值
         */
        public void setFieldValue(String key, String field, Object value) {
            if (key == null || field == null || value == null) return;
            ops.put(key, field, value);
        }

        /**
         * 仅当字段不存在时，在 Hash 中设置一个字段的值 (HSETNX)
         *
         * @param key   键
         * @param field 字段
         * @param value 值
         * @return 如果设置成功返回 true, 字段已存在则返回 false
         */
        public boolean setFieldValueIfAbsent(String key, String field, Object value) {
            if (key == null || field == null || value == null) return false;
            return ops.putIfAbsent(key, field, value);
        }

        /**
         * 批量在 Hash 中设置多个字段的值 (HMSET)
         *
         * @param key 键
         * @param map 包含多个字段和值的 Map
         */
        public void setMultipleFields(String key, Map<String, Object> map) {
            if (key == null || map == null || map.isEmpty()) return;
            ops.putAll(key, map);
        }

        /**
         * 批量在 Hash 中设置多个字段的值，并为整个 Hash 设置过期时间
         *
         * @param key     键
         * @param map     包含多个字段和值的 Map
         * @param timeout 过期时间
         * @param unit    时间单位
         */
        public void setMultipleFieldsAndExpire(String key, Map<String, Object> map, long timeout, TimeUnit unit) {
            if (key == null || map == null || map.isEmpty()) return;
            ops.putAll(key, map);
            redisTemplate.expire(key, timeout, unit);
        }

        /**
         * 获取 Hash 中指定字段的值 (HGET)
         *
         * @param key   键
         * @param field 字段
         * @return 字段对应的值
         */
        @SuppressWarnings("unchecked")
        public <T> T getFieldValue(String key, String field) {
            if (key == null || field == null) return null;
            return (T) ops.get(key, field);
        }

        /**
         * 批量获取 Hash 中多个字段的值 (HMGET)
         *
         * @param key    键
         * @param fields 字段集合
         * @return 值的列表，顺序与传入字段一致
         */
        public List<Object> getMultipleFields(String key, Collection<Object> fields) {
            if (key == null || fields == null || fields.isEmpty()) return Collections.emptyList();
            return ops.multiGet(key, fields);
        }

        /**
         * 获取 Hash 中所有的字段和值 (HGETALL)
         *
         * @param key 键
         * @return 包含所有字段和值的 Map
         */
        public Map<Object, Object> getAllFieldsAndValues(String key) {
            if (key == null) return Collections.emptyMap();
            return ops.entries(key);
        }

        /**
         * 获取 Hash 中所有的字段名 (HKEYS)
         *
         * @param key 键
         * @return 所有字段名的 Set
         */
        public Set<Object> getAllFields(String key) {
            if (key == null) return Collections.emptySet();
            return ops.keys(key);
        }

        /**
         * 获取 Hash 中所有的值 (HVALS)
         *
         * @param key 键
         * @return 所有值的 List
         */
        public List<Object> getAllValues(String key) {
            if (key == null) return Collections.emptyList();
            return ops.values(key);
        }

        /**
         * 删除 Hash 中的一个或多个字段 (HDEL)
         *
         * @param key    键
         * @param fields 要删除的字段
         * @return 成功删除的字段数量
         */
        public Long deleteFields(String key, Object... fields) {
            if (key == null || fields == null || fields.length == 0) return 0L;
            return ops.delete(key, fields);
        }

        /**
         * 检查 Hash 中是否存在指定的字段 (HEXISTS)
         *
         * @param key   键
         * @param field 字段
         * @return true 表示存在
         */
        public boolean fieldExists(String key, String field) {
            if (key == null || field == null) return false;
            return ops.hasKey(key, field);
        }

        /**
         * 对 Hash 中指定字段的整数值进行原子增加 (HINCRBY)
         *
         * @param key   键
         * @param field 字段
         * @param delta 增加的数值
         * @return 增加后的值
         */
        public Long incrementFieldBy(String key, String field, long delta) {
            if (key == null || field == null) return null;
            return ops.increment(key, field, delta);
        }

        /**
         * 对 Hash 中指定字段的浮点数值进行原子增加 (HINCRBYFLOAT)
         *
         * @param key   键
         * @param field 字段
         * @param delta 增加的浮点数值
         * @return 增加后的值
         */
        public Double incrementFieldByFloat(String key, String field, double delta) {
            if (key == null || field == null) return null;
            return ops.increment(key, field, delta);
        }

        /**
         * 获取 Hash 中的字段数量 (HLEN)
         *
         * @param key 键
         * @return 字段数量
         */
        public Long getFieldCount(String key) {
            if (key == null) return 0L;
            return ops.size(key);
        }
    }


    // ==================== List (列表) 操作 ====================

    public static class ListOps {

        private final ListOperations<String, Object> ops;
        private final RedisTemplate<String, Object> redisTemplate;

        public ListOps(ListOperations<String, Object> ops, RedisTemplate<String, Object> redisTemplate) {
            this.ops = ops;
            this.redisTemplate = redisTemplate;
        }

        /**
         * 从列表右侧推入一个或多个元素 (RPUSH)
         *
         * @param key    键
         * @param values 要推入的元素
         * @return 推入后列表的长度
         */
        public Long pushToRight(String key, Object... values) {
            if (key == null || values == null || values.length == 0) return 0L;
            return ops.rightPushAll(key, values);
        }

        /**
         * 从列表左侧推入一个或多个元素 (LPUSH)
         *
         * @param key    键
         * @param values 要推入的元素
         * @return 推入后列表的长度
         */
        public Long pushToLeft(String key, Object... values) {
            if (key == null || values == null || values.length == 0) return 0L;
            return ops.leftPushAll(key, values);
        }

        /**
         * 从列表右侧推入元素，并设置过期时间
         *
         * @param key     键
         * @param timeout 过期时间
         * @param unit    时间单位
         * @param values  元素
         */
        public void pushToRightAndExpire(String key, long timeout, TimeUnit unit, Object... values) {
            if (key == null || values == null || values.length == 0) return;
            ops.rightPushAll(key, values);
            redisTemplate.expire(key, timeout, unit);
        }

        /**
         * 从列表左侧推入元素，并设置过期时间
         *
         * @param key     键
         * @param timeout 过期时间
         * @param unit    时间单位
         * @param values  元素
         */
        public void pushToLeftAndExpire(String key, long timeout, TimeUnit unit, Object... values) {
            if (key == null || values == null || values.length == 0) return;
            ops.leftPushAll(key, values);
            redisTemplate.expire(key, timeout, unit);
        }

        /**
         * 从列表右侧弹出一个元素 (RPOP)
         *
         * @param key 键
         * @return 弹出的元素
         */
        @SuppressWarnings("unchecked")
        public <T> T popFromRight(String key) {
            if (key == null) return null;
            return (T) ops.rightPop(key);
        }

        /**
         * 从列表左侧弹出一个元素 (LPOP)
         *
         * @param key 键
         * @return 弹出的元素
         */
        @SuppressWarnings("unchecked")
        public <T> T popFromLeft(String key) {
            if (key == null) return null;
            return (T) ops.leftPop(key);
        }

        /**
         * 阻塞式地从列表右侧弹出一个元素 (BRPOP)
         *
         * @param key     键
         * @param timeout 等待超时时间
         * @param unit    时间单位
         * @return 弹出的元素，超时则返回 null
         */
        @SuppressWarnings("unchecked")
        public <T> T blockPopFromRight(String key, long timeout, TimeUnit unit) {
            if (key == null) return null;
            return (T) ops.rightPop(key, timeout, unit);
        }

        /**
         * 阻塞式地从列表左侧弹出一个元素 (BLPOP)
         *
         * @param key     键
         * @param timeout 等待超时时间
         * @param unit    时间单位
         * @return 弹出的元素，超时则返回 null
         */
        @SuppressWarnings("unchecked")
        public <T> T blockPopFromLeft(String key, long timeout, TimeUnit unit) {
            if (key == null) return null;
            return (T) ops.leftPop(key, timeout, unit);
        }

        /**
         * 获取列表指定范围内的所有元素 (LRANGE)
         *
         * @param key   键
         * @param start 起始索引 (0 为第一个)
         * @param end   结束索引 (-1 为最后一个)
         * @return 范围内的元素列表
         */
        public List<Object> getRange(String key, long start, long end) {
            if (key == null) return Collections.emptyList();
            return ops.range(key, start, end);
        }

        /**
         * 修剪列表，只保留指定范围内的元素 (LTRIM)
         *
         * @param key   键
         * @param start 起始索引
         * @param end   结束索引
         */
        public void trim(String key, long start, long end) {
            if (key == null) return;
            ops.trim(key, start, end);
        }

        /**
         * 获取列表的长度 (LLEN)
         *
         * @param key 键
         * @return 列表长度
         */
        public Long getLength(String key) {
            if (key == null) return 0L;
            return ops.size(key);
        }

        /**
         * 获取列表在指定索引位置的元素 (LINDEX)
         *
         * @param key   键
         * @param index 索引
         * @return 元素
         */
        @SuppressWarnings("unchecked")
        public <T> T getElementAtIndex(String key, long index) {
            if (key == null) return null;
            return (T) ops.index(key, index);
        }

        /**
         * 设置列表在指定索引位置的元素值 (LSET)
         *
         * @param key   键
         * @param index 索引
         * @param value 新的值
         */
        public void setElementAtIndex(String key, long index, Object value) {
            if (key == null || value == null) return;
            ops.set(key, index, value);
        }

        /**
         * 从列表中移除指定数量的匹配元素 (LREM)
         *
         * @param key   键
         * @param count 移除数量 ( > 0: 从头开始, < 0: 从尾开始, = 0: 移除所有)
         * @param value 要移除的元素值
         * @return 成功移除的元素数量
         */
        public Long removeMatchingElements(String key, long count, Object value) {
            if (key == null || value == null) return 0L;
            return ops.remove(key, count, value);
        }
    }


    // ==================== ZSet (有序集合) 操作 ====================

    public static class ZSetOps {

        private final ZSetOperations<String, Object> ops;
        private final RedisTemplate<String, Object> redisTemplate;

        public ZSetOps(ZSetOperations<String, Object> ops, RedisTemplate<String, Object> redisTemplate) {
            this.ops = ops;
            this.redisTemplate = redisTemplate;
        }

        /**
         * 向 ZSet 中添加一个成员，或更新其分数 (ZADD)
         *
         * @param key    键
         * @param member 成员
         * @param score  分数
         * @return 是否成功添加
         */
        public Boolean addMember(String key, Object member, double score) {
            if (key == null || member == null) return false;
            return ops.add(key, member, score);
        }

        /**
         * 向 ZSet 中批量添加成员 (ZADD)
         *
         * @param key    键
         * @param tuples 成员和分数的元组集合
         * @return 成功添加的成员数量
         */
        public Long addMembers(String key, Set<ZSetOperations.TypedTuple<Object>> tuples) {
            if (key == null || tuples == null || tuples.isEmpty()) return 0L;
            return ops.add(key, tuples);
        }

        /**
         * 批量添加成员并设置 Key 的过期时间
         *
         * @param key     键
         * @param tuples  成员-分数元组集合
         * @param timeout 过期时间
         * @param unit    时间单位
         * @return 成功添加的成员数量
         */
        public Long addMembersAndExpire(String key, Set<ZSetOperations.TypedTuple<Object>> tuples, long timeout, TimeUnit unit) {
            if (key == null || tuples == null || tuples.isEmpty()) return 0L;
            Long count = ops.add(key, tuples);
            redisTemplate.expire(key, timeout, unit);
            return count;
        }

        /**
         * 移除 ZSet 中的一个或多个成员 (ZREM)
         *
         * @param key     键
         * @param members 成员
         * @return 成功移除的成员数量
         */
        public Long removeMembers(String key, Object... members) {
            if (key == null || members == null || members.length == 0) return 0L;
            return ops.remove(key, members);
        }

        /**
         * 增加指定成员的分数 (ZINCRBY)
         *
         * @param key    键
         * @param member 成员
         * @param delta  增加的分数（可为负）
         * @return 成员新的分数
         */
        public Double incrementScoreOfMember(String key, Object member, double delta) {
            if (key == null || member == null) return null;
            return ops.incrementScore(key, member, delta);
        }

        /**
         * 获取指定成员的分数 (ZSCORE)
         *
         * @param key    键
         * @param member 成员
         * @return 成员的分数
         */
        public Double getScoreOfMember(String key, Object member) {
            if (key == null || member == null) return null;
            return ops.score(key, member);
        }

        /**
         * 获取成员在 ZSet 中的排名（按分数升序，从 0 开始）(ZRANK)
         *
         * @param key    键
         * @param member 成员
         * @return 排名
         */
        public Long getRankAsc(String key, Object member) {
            if (key == null || member == null) return null;
            return ops.rank(key, member);
        }

        /**
         * 获取成员在 ZSet 中的排名（按分数降序，从 0 开始）(ZREVRANK)
         *
         * @param key    键
         * @param member 成员
         * @return 排名
         */
        public Long getRankDesc(String key, Object member) {
            if (key == null || member == null) return null;
            return ops.reverseRank(key, member);
        }

        /**
         * 获取 ZSet 中指定排名范围的成员（按分数升序）(ZRANGE)
         *
         * @param key   键
         * @param start 起始排名
         * @param end   结束排名
         * @return 成员集合
         */
        public Set<Object> getMembersByRankRangeAsc(String key, long start, long end) {
            if (key == null) return Collections.emptySet();
            return ops.range(key, start, end);
        }

        /**
         * 获取 ZSet 中指定排名范围的成员（按分数降序）(ZREVRANGE)
         *
         * @param key   键
         * @param start 起始排名
         * @param end   结束排名
         * @return 成员集合
         */
        public Set<Object> getMembersByRankRangeDesc(String key, long start, long end) {
            if (key == null) return Collections.emptySet();
            return ops.reverseRange(key, start, end);
        }

        /**
         * 获取 ZSet 中指定分数范围的成员（按分数升序）(ZRANGEBYSCORE)
         *
         * @param key 键
         * @param min 最小分数
         * @param max 最大分数
         * @return 成员集合
         */
        public Set<Object> getMembersByScoreRange(String key, double min, double max) {
            if (key == null) return Collections.emptySet();
            return ops.rangeByScore(key, min, max);
        }

        /**
         * 获取 ZSet 中指定排名范围的成员及其分数（按分数升序）(ZRANGE WITHSCORES)
         *
         * @param key   键
         * @param start 起始排名
         * @param end   结束排名
         * @return 带分数的成员元组集合
         */
        public Set<ZSetOperations.TypedTuple<Object>> getMembersWithScoresByRankRangeAsc(String key, long start, long end) {
            if (key == null) return Collections.emptySet();
            return ops.rangeWithScores(key, start, end);
        }

        /**
         * 获取 ZSet 的大小（成员数量）(ZCARD)
         *
         * @param key 键
         * @return 成员数量
         */
        public Long getMemberCount(String key) {
            if (key == null) return 0L;
            return ops.size(key);
        }

        /**
         * 获取 ZSet 中指定分数范围内的成员数量 (ZCOUNT)
         *
         * @param key 键
         * @param min 最小分数
         * @param max 最大分数
         * @return 成员数量
         */
        public Long getCountByScoreRange(String key, double min, double max) {
            if (key == null) return 0L;
            return ops.count(key, min, max);
        }

        /**
         * 移除 ZSet 中指定排名范围的成员 (ZREMRANGEBYRANK)
         *
         * @param key   键
         * @param start 起始排名
         * @param end   结束排名
         * @return 移除的成员数量
         */
        public Long removeMembersByRankRange(String key, long start, long end) {
            if (key == null) return 0L;
            return ops.removeRange(key, start, end);
        }

        /**
         * 移除 ZSet 中指定分数范围的成员 (ZREMRANGEBYSCORE)
         *
         * @param key 键
         * @param min 最小分数
         * @param max 最大分数
         * @return 移除的成员数量
         */
        public Long removeMembersByScoreRange(String key, double min, double max) {
            if (key == null) return 0L;
            return ops.removeRangeByScore(key, min, max);
        }
    }


    // ==================== Keys (通用) 操作 ====================

    public static class KeysOps {

        private final RedisTemplate<String, Object> redisTemplate;

        public KeysOps(RedisTemplate<String, Object> redisTemplate) {
            this.redisTemplate = redisTemplate;
        }

        /**
         * 删除指定的 Key (DEL)
         *
         * @param key 键
         * @return 是否删除成功
         */
        public boolean delete(String key) {
            if (key == null) return false;
            return Boolean.TRUE.equals(redisTemplate.delete(key));
        }

        /**
         * 批量删除多个 Key (DEL)
         *
         * @param keys 键的集合
         * @return 成功删除的 Key 的数量
         */
        public Long deleteMultiple(Collection<String> keys) {
            if (keys == null || keys.isEmpty()) return 0L;
            return redisTemplate.delete(keys);
        }

        /**
         * 检查指定的 Key 是否存在 (EXISTS)
         *
         * @param key 键
         * @return true 表示存在
         */
        public boolean hasKey(String key) {
            if (key == null) return false;
            return Boolean.TRUE.equals(redisTemplate.hasKey(key));
        }

        /**
         * 为指定的 Key 设置过期时间 (EXPIRE)
         *
         * @param key     键
         * @param timeout 过期时间数值
         * @param unit    时间单位
         * @return 是否设置成功
         */
        public boolean setExpiration(String key, long timeout, TimeUnit unit) {
            if (key == null) return false;
            return redisTemplate.expire(key, timeout, unit);
        }

        /**
         * 获取 Key 的剩余过期时间 (TTL)
         *
         * @param key  键
         * @param unit 返回的时间单位
         * @return 剩余过期时间。-2 表示 Key 不存在，-1 表示永不过期。
         */
        public Long getRemainingTimeToLive(String key, TimeUnit unit) {
            if (key == null) return -2L;
            return redisTemplate.getExpire(key, unit);
        }

        /**
         * 移除 Key 的过期时间，使其永久有效 (PERSIST)
         *
         * @param key 键
         * @return 是否成功移除
         */
        public boolean persistKey(String key) {
            if (key == null) return false;
            return Boolean.TRUE.equals(redisTemplate.persist(key));
        }

        /**
         * 扫描匹配模式的 Key (SCAN)。
         * 注意：在生产环境中应谨慎使用，避免一次性扫描大量 Key 导致性能问题。
         *
         * @param pattern 匹配模式 (如: "user:*")
         * @param count   每次扫描的数量 hint
         * @return 匹配的 Key 集合
         */
        public Set<String> scanForKeys(String pattern, int count) {
            if (pattern == null) return Collections.emptySet();
            Set<String> keys = new HashSet<>();
            ScanOptions options = ScanOptions.scanOptions().match(pattern).count(count).build();
            try (Cursor<String> cursor = redisTemplate.scan(options)) {
                while (cursor.hasNext()) {
                    keys.add(cursor.next());
                }
            }
            return keys;
        }

        /**
         * 获取 Key 的数据类型 (TYPE)
         *
         * @param key 键
         * @return 数据类型 (STRING, LIST, SET, ZSET, HASH)
         */
        public DataType getKeyType(String key) {
            if (key == null) return DataType.NONE;
            return redisTemplate.type(key);
        }

        /**
         * 重命名 Key (RENAME)
         *
         * @param oldKey 旧键名
         * @param newKey 新键名
         */
        public void renameKey(String oldKey, String newKey) {
            if (oldKey == null || newKey == null) return;
            redisTemplate.rename(oldKey, newKey);
        }
    }
}